#ifndef DPGMTRACKING_H
#define DPGMTRACKING_H

#include <QtGui/QMainWindow>
#include "ui_dpgmtracking.h"
#include "YK16GrayImage.h"
#include "snake.h"

#include <QTimer>
#include <QThread>
#include <QMutex>
#include <QPoint>

class YKThreadGetImg;
class YKThreadProcImg;

class QXmlStreamReader;
class DlgStructure3D;

using namespace std;

struct PIXINFO{
	unsigned short posX;
	unsigned short posY;
	float val;
};

struct FLEXDATA{
	float fGanAngle; //MV beam gantry angle
	float fPanelOffsetX; //MV beam gantry angle
	float fPanelOffsetY; //MV beam gantry angle	
	bool bKVBeamOn;
	bool bMVBeamOn;
	int iXVIElapseMS;
};


struct VEC3D{
	float fX; //MV beam gantry angle
	float fY; //MV beam gantry angle
	float fZ; //MV beam gantry angle	
};

struct VEC2D{
	float fX; //MV beam gantry angle
	float fY; //MV beam gantry angle
};

enum EN_PROJ_IMG_TYPE{
	PI_IRIS = 0,
	PI_FULL_ELEKTA,
	PI_HALF_ELEKTA,
	PI_UNKNOWN,
};

enum UPDATE_DIRECTION{
    UT_DATA2TABLE = 0,
    UT_TABLE2DATA,    
};


struct IMGPROC_PARAMSET
{
	float preGaussGamma;
	int windUpper;
	int windLower;
	int derivateY_threPerc;
	int derivateLine_threPerc;
	int sobel_threPerc;
	float postGaussGamma;
	int binary_threPerc;
	int median_window;
	int CC_overlap;
};


struct STRUCT_PROPT{
    int structID;
    QString structName;
    VEC3D fColor;
    int iNumOfPoints;

    int iThick2D; //line thickness
    int iThick3D;

    bool bVisible2D;//should be revisited if precalculation of 2D contour is implemented (all the 2D contour data can be precalculated)
    bool bVisible3D;

    int iSparsity2D;
    int iSparsity3D;// this is sparsity in SI direction//precoded for Skin structures = 10

    bool bMotionEnable2D; //as a default, it is false
    bool bMotionEnable3D; //false
};


class QStandardItemModel;
//class CSnake;


#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkDerivativeImageFilter.h"
#include "itkSmoothingRecursiveGaussianImageFilter.h"
#include "itkIntensityWindowingImageFilter.h"
#include "itkSobelEdgeDetectionImageFilter.h"
#include "itkMedianImageFilter.h"


//#include "dcmtk_rt_study.h"
//#include "plm_image.h"
//#include "plm_image_type.h"
//#include "rtss_contour.h"
//#include "rtss_roi.h"

class YK16GrayImage;
class QTimer;
class Dcmtk_rt_study;
class Rtss_roi;

#define MAX_LINE_LENGTH 1024

#define IRIS_WIDTH 2048
#define IRIS_HEIGHT 1536

#define ELEKTA_WIDTH 1024
#define ELEKTA_HEIGHT 1024

#define HALF_ELEKTA_WIDTH 512
#define HALF_ELEKTA_HEIGHT 512

#define ELEKTA_SAD 1000.0
#define ELEKTA_SID 1536.0

#define YKPI 3.141592

#define DEFAULT_VOL_INDEX 500.0 // correspond to minAngGap of 20        
#define DEFAULT_SPARSITY_FACTOR 2.0//20 deg 

typedef itk::Image<float,2> FloatImageTypeYK;
typedef itk::Image<unsigned short, 2> UnsignedShortImageType;
typedef itk::ImageFileReader<UnsignedShortImageType> readerType;
typedef itk::DerivativeImageFilter<UnsignedShortImageType, FloatImageTypeYK> filterType;
typedef itk::SmoothingRecursiveGaussianImageFilter<UnsignedShortImageType, UnsignedShortImageType>  SmoothingFilterType;
typedef itk::IntensityWindowingImageFilter<UnsignedShortImageType, UnsignedShortImageType>  WindowingFilterType;

typedef itk::MedianImageFilter<UnsignedShortImageType, UnsignedShortImageType>  MedianFilterType;
typedef itk::ImageFileWriter<UnsignedShortImageType> writerType;

typedef itk::SobelEdgeDetectionImageFilter<UnsignedShortImageType, FloatImageTypeYK>  EdgeFilterType;

class DPGMTracking: public QMainWindow
{
	Q_OBJECT

public:
	DPGMTracking(QWidget *parent = 0, Qt::WFlags flags = 0);
	~DPGMTracking();	
	void ReleaseMemory();
	bool RunSnakeForLoop();
	//void FillCurrentROI();	//ROI spacing is defined here!. Dont care full image spacing.
	void FillCurrentROI(YK16GrayImage* pYKImageFull, YK16GrayImage* pYKImageROI); //should be called after ResetROIExt
	void GaussianSmoothing(YK16GrayImage* pYKImageROI, double fSigma);
	void IntensityWindowing(YK16GrayImage* pYKImageROI, int srcMin, int srcMax, int tarMin, int tarMax);
	void FirstDerivative_Y(YK16GrayImage* pYKImageROI, int threPercent);
	void FirstDerivative_Y_Line(YK16GrayImage* pYKImageROI, int threPercent);
	void SobelEdgeDetection(YK16GrayImage* pYKImageROI, int threPercent);
	void BinaryImage(YK16GrayImage* pYKImageROI, int threshold);
	void MedianFiltering(YK16GrayImage* pYKImageROI, int winSize);
	void FFT_NormalizedCrossCorrelation(YK16GrayImage* pYKImageROI, int iReqNumOverlapPix);
		
	//void ImgProcessingForROI(QString* pYKImage, QString* pYKImageROI, QString strCommand);//Previous name: prepare for SNAKE. 

	//void SheetnessFiltering(double sigma, double sheetnessNorm, double BoobinessNorm, double NoiseNorm, bool detectBrightSheet);	
	void CreateTemplate(int sizeX, int sizeY, float spacingX, float spacingY);
	

	//Merged from ElektaTracking
	//void RunGetDataFromServer();
	void RunProcessData();
	void SetThreadProcPointer(YKThreadProcImg* pProcThread, int idx);

	// determine m_fDefaultSpacingX, m_fDefaultSpacingY using image dimension	
	void SetDefaultImageDimension(EN_PROJ_IMG_TYPE enType);

	//Merged from ElektaTracking
	HANDLE m_hSemaphore;
	//bool m_continue;
	int m_iLastIdx; //
	int m_iLastProcessedIdx; //this will be updated by ThredProc. 0-based. This idx will be used by DrawProjImg using TIMER
	//In File based simulation mode, this value will remain as -1 and current spin index will be used for DrawProj

	int m_iCntMaxImg;
	bool m_bOnProcessing;

	YKThreadGetImg* m_pThreadGetImg;
	YK16GrayImage* m_arrYKImage; //independent raw images
	YK16GrayImage* m_arrYKImageROI;
	YKThreadProcImg** m_pArrThreadProc;

	//YK16GrayImage m_dspYKImage;
	QTimer* m_timerDisplay;
	bool m_bTimerBusy;
	int m_iDspTimerInterval;
	QMutex m_mutex;


	//comes from DPGMTracking
	int m_iImgCnt;	
	//YK16GrayImage* m_pImageYKCurROI; //this should be array

	float m_fDefaultSpacingX;
	float m_fDefaultSpacingY;

	QStandardItemModel *m_pTableModel;
	QTimer* m_timerSnakeDebug;
	QTimer* m_timerDiaTracking;

	EN_PROJ_IMG_TYPE m_enProjImageType;
	float m_fDisplay_ratio;

        Dcmtk_rt_study* m_pRTstudy;
	//QPoint m_ptMatchPos;

	//vector<PIXINFO> m_vMarkerPosROI_A; //CAUTION: This is for ROI dimension and volatile (updated after a single processing) // Don't need to be a member variable!! YKdebug. will be replaced by local one
	//vector<PIXINFO> m_vMarkerPosROI_B; //final number of markers //CAUTION: This is for ROI dimension and volatile (updated after a single processing)
	//int m_iRequiredMarker;

	//void Update2DRefMarkerPos();
	//void ResetROI(int fullWidth, int fullHeight, int ROI_width, int ROI_height, QPoint& centerPt);	

	void ResetROIByDefault(YK16GrayImage* pYKImage); //for current image only	
	void ResetROI(int dataPosX, int dataPosY); //for current image only	
	void ResetROIAll(int dataPosX, int dataPosY); //used in simulation mode only
	void ResetROIExt(YK16GrayImage* pYKImage, int marginLt, int marginTop, int marginRt, int marginBottom); //for current image only	

	//This is called from Timer event. This is combination of image processing
	void ImgProcessingForROI(YK16GrayImage* pYKImage, YK16GrayImage* pYKImageROI);//Previous name: prepare for SNAKE. 
	//This is called from Timer event. This is combination of image processing
	void ImgProcessingForROI(YK16GrayImage* pYKImage, YK16GrayImage* pYKImageROI, IMGPROC_PARAMSET& stParamset);	
	void FindMarkerInROI_A(YK16GrayImage* pImageYKFull, YK16GrayImage* pImageYKCurROI, vector<PIXINFO>& vOutputMarker, float fThreMultiplySD, float sameMarkerMargin);

	double FindMarkerInROI_B(YK16GrayImage* pImageYKFull, YK16GrayImage* pImageYKCurROI,
		vector<PIXINFO>& vInputMarkerWithCC, int iCandidate, int iNumOfTrackMarker,
		double motionW_X, double motionW_Y, double CC_weighting, vector<QPoint>& vPrevFrameMarkerPos);

	void printMotionLog(QString& strFilePath);
	


	FLEXDATA XML_parseFrameForXVI5(QXmlStreamReader& xml);
	QString XML_GetSingleItemString(QXmlStreamReader& xml);

        void GetPoint3DFromDcmtkByName(Dcmtk_rt_study* pRTStudy, QString strROIName, vector<VEC3D>& vOutputPt3D);
        void GetPoint3DFromDcmtkSingleROI(Rtss_roi* pRtss_roi, vector<VEC3D>& vOutputPt3D);

        VEC3D GetRGBFomDCMStr(const char* colorstr);

        //void UpdateStructureTable();
        void UpdateStructureTable(UPDATE_DIRECTION enUpdateDirection);

        void LoadRTStruct(QString strPath);

	public slots:		
		void SLT_OpenMultipleFiles(); //for IRIS imags
		void SLT_DrawGraph();		
		void SLT_ExportCurrentGraph();
		//void SLT_UpdateTable();
		void SLT_CopyTableSelectionToClipBoard();		
		//void SLT_DrawCurrentImage(int ROIwindowMin, int ROIwindowMax);
		//void SLT_CopyOriginalToCurrent(); //only called when spin box is changed //here, current image copies original one		
		//void SLT_FillCurrentROIFromSrc();		
		void SLT_BtnGetROIImage();
		void SLT_GaussianSmoothingPre();
		void SLT_IntensityWindowing();
		void SLT_FirstDerivative_Y();
		void SLT_FirstDerivative_Y_Line();
		void SLT_SobelEdgeDetection();		
		void SLT_GaussianSmoothingPost();	
		void SLT_BinaryImage();
		void SLT_MedianFiltering();		

		void SLT_RunSnake(); //after, move to while loop or thread
		void timerSnakeDebug_event();
		void SLT_Snake_Simulation_Timer_On();
		void SLT_Snake_Simulation_Timer_Off();

		void SLT_InitSnake();
		void SLT_LoadDefaultSnake();
		void SLT_GoWhileLoop();
		void SLT_ShowPixelValue();

		void SLT_StartRecordROI();
		void SLT_EndRecordROI();		
		
		void SLT_TrackingStart();//Tracking Timer Start
		void SLT_TrackingStop();		
		

		void SLT_PrepareDspImg();

		//Slider Min / Max s
		void SLT_AdjustDrawForWindow(); //should be deleted later.

		//Merged from ElektaTracking
		void SLTM_StartSync();
		void SLTM_StopSync();		
		
		void SLT_TimerDisplayInSyncMode(); //Just drawing image purpose in multi-thread concept
		void SLT_ExportTimeStamp();

		void SLT_FFTNormCC();
		
		void SLT_FindFiducialMarker();//Using Thread
		void SLT_GenTemplate();

		void SLT_ImgProcessingForROI();

		//when click Trakcking option Radio buttons
		void SLT_SetDefaultTrackingParams();
		void SLT_SetFlexmap();
		void SLT_SetMarkerPosDICOM();
		void SLT_BtnResetSyncIdx();

                void SLTM_LoadRTStruct();

                
                void timerDiaTracking_event();//Tracking simulation purpose. Should be compied to ImgProc
                //Set m_pCurImage from main database and Draw it
                void SLT_DrawProjImage();

                void SLTM_ShowDlgStructure();
public:
	QVector<QColor> m_ColorGen;
	
	int m_iWidth;
	int m_iHeight;

	UnsignedShortImageType::Pointer m_spSrcImage;	
	QPoint View2Data(QPoint viewPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight);
	QPoint Data2View(QPoint dataPt, int viewWidth, int viewHeight, int dataWidth, int dataHeight);

	UnsignedShortImageType::Pointer m_spCCTemplate;//2D template

public: //SNAKE
	CSnake* m_pSnake0;
	CSnake* m_pSnake1;
	CSnake* m_pSnake2;

	//ROI param is only needed for Record ROI
	int m_iROILeft;
	int m_iROITop;
	int m_iROIRight;
	int m_iROIBottom;

	bool m_bROIRecordStarted;

	//vector<QPointF> m_vDiaTrackingData; //current: mean value
	QTime m_DiaTrackingStartTime;
	QTime m_DiaTrackingCurTime;

	//bool m_bDisplayROI8Bit; //applies to m_pImageYKCurROI. Turns on when (either Window Filtering, Y_derivative, Derivative lIne, Sobel, Binary, CrossCorr is called)s
	//Initialized(to be false) when FillROI (Get ROI Image) is called
	
	//Flexmap for retrospecive analysis
	vector<FLEXDATA> m_vRetroFlexmap; //only used for retrospective analysis. In real-time case, those data are transferred from XVI 
	vector<VEC3D> m_vRefMarkerPosDCM;// mm, DICOM
	//vector<QPoint> m_vRefMarkerPos2D; //Y direction is diff. from DCM. Updated from Timer event (or image update event acc. to gantry angle)

	QPoint Get2DPosFromDCM3D(float DCM_X, float DCM_Y, float DCM_Z, float MV_GanAngle, float panelOffsetX, float panelOffsetY, float fSAD, float fSID, float width2D, float height2D, float spX, float spY);

        //VEC3D GetTransformedDCM3DFromRawDCM(VEC3D curPosDCM, VEC3D planIsoDCM, VEC3D couchTrans, VEC3D couchRotDeg); //couchRotDeg: Pitch,Yaw, Roll order
        VEC3D GetTransformedDCM3DFromRawDCM(VEC3D curPosDCM, VEC3D planIsoDCM, VEC3D couchTrans, VEC3D couchRotDeg);
        //Get transf information from UI directly
        VEC3D GetTransformedDCM3DFromRawDCM(VEC3D curPosDCM);

        //iSparsityLevel: 1: default->200 3Dpoints --> anglegap20, 2-> anglegap-->10deg
        void FillUp2DContours(YK16GrayImage& YKImg, Dcmtk_rt_study* pRTStudy, VEC3D& planIsoDCM,
            VEC3D& couchTrans, VEC3D& couchRotDeg,
            FLEXDATA& flxData, int width2D, int height2D, float spacingX, float spacingY, vector<STRUCT_PROPT>& vStructProperty);

	void Combination(std::vector<int>& vIndex, int combCnt, std::vector<int>& vOutputComb); //vIndex will be all candidates
	//void Permutation(std::vector<int>& vIndex, int permuCnt, std::vector<int>& vOutputPermu);//vIndex size will be same as combCnt
	double ComputeMinVecDiffAndSortIndex(vector<int>& vTestIndex, vector<QPoint>& vMarkerPosRef, vector<QPoint>& vMarkerPosComp);
	double GetMeanVecDiff(vector<QPoint>& vMarkerPosRef, vector<QPoint>&vMarkerPosComp);
	bool m_bDisplayTimerOn;


        VEC3D m_motionDelta; //3D motion diff from Ref Point. jUst for display. should be updated after pdf based tracking is implemented
        DlgStructure3D* m_pDlgStructure;

        vector<STRUCT_PROPT> m_vStructProperty;
        
            
	

public:
	Ui::DPGMTrackingClass ui;
};

#endif // BADPIXELDETECTOR_H